#pragma once

#include <string>
#include <unordered_map>
#include <vector>
#include <cstring>
#include <sstream>

#include"Tool.hpp"
#include "Logger.hpp"

using namespace std;
using namespace LogMudule;

//这个模块是HTTP响应数据模块，用于业务处理后设置并保存HTTP响应数据的的各项元素信息
class HttpResponse
{
public:
    // 状态码
    int _status_code;
    // 协议版本
    string _version;
    // 响应报头
    unordered_map<string, string> _headers;
    // 响应正文
    string _body;

public:
    HttpResponse()
        : _status_code(200),
          _version("HTTP/1.1")
    {
    }
    // 插入响应报头(如果存在key就更新,如果不存在key,就直接插入)
    void InsertHead(const string &key, const string &val)
    {
        // 如果存在key就更新
        // 如果不存在key,就直接插入
        _headers[key] = val;
    }
    // 判断指定响应报头是否存在
    bool HasHead(const string &key)
    {
        // 如果不存在
        if (_headers.find(key) == _headers.end())
        {
            return false;
        }
        else // 如果存在
        {
            return true;
        }
    }
    // 获取指定响应报头的value
    string GetHead(const string &key)
    {
        if (HasHead(key))
        {
            return _headers[key];
        }
        else
        {
            LOG(LogLevel::DEBUG) << "访问的请求报头: " << key << "不存在";
            return "";
        }
    }
    // 是否为短连接
    bool IsShortConnections()
    {
        //如果没有Connection头部字段或者有该字段但是val为close
        //那么就是短连接
        if(HasHead("Connection")==false)
        {
            return true;
        }
        else if(GetHead("Connection")=="close")
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    // 重置当前HttpResponse对象
    void ReSet()
    {
        _status_code=200;
        _version.clear();
        _headers.clear();
        _body.clear();
    }
    // 设置响应正文并指定正文类型和正文长度
    void SetBody(const string &body, const string &type)
    {
        //设置响应正文
        _body=body;

        //正文类型,添加到响应报头
        _headers["Content-Type"]=type;
        // 填充响应头部
        InsertHead("Content-Length", to_string(_body.size()));
    }

    // 设置状态码
    void SetStatusCode(int code)
    {
        _status_code=code;
    }
    // 设置协议版本
    void SetVersion(const string &version)
    {
        _version=version;
    }
    // 设置重定向的路径和重定向状态码,并添加到响应头部字段
    void SetRedirect(const string &url, int statu)
    {
        //设置重定向状态码
        _status_code=statu;

        //把重定向字段添加到报头,并对uri编码
        _headers["Location"]=Tool::UrlEncode(url,true);
    }

    //序列化
    string Serialization()
    {
        stringstream ss;

        //序列化响应行
        ss<<_version<<" "<<_status_code<<" "<<Tool::StatusCodeDescription(_status_code)<<"\r\n";

        //序列化响应报头
        for(const auto &e:_headers)
        {
            ss<<e.first<<": "<<e.second<<"\r\n";
        }
        //添加空行
        ss<<"\r\n";

        //添加正文
        ss<<_body;
        return ss.str();
    }
};
